package com.yf.tz.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.gc.server.dao.LevelDao;
import com.gc.server.dao.UserDao;
import com.gc.server.entity.LevelEntity;
import com.gc.server.entity.UserEntity;
import com.github.pagehelper.PageHelper;
import com.yf.consts.Constant;
import com.yf.response.RRException;
import com.yf.service.WxNoticeService;
import com.yf.service.WxPayService;
import com.yf.service.impl.BaseServiceImpl;
import com.yf.tz.common.Const;
import com.yf.tz.dao.*;
import com.yf.tz.entity.*;
import com.yf.tz.enums.*;
import com.yf.tz.service.AccountService;
import com.yf.tz.service.MallGoodsService;
import com.yf.tz.service.MallOrderService;
import com.yf.tz.service.ServerConfigService;
import com.yf.tz.vo.MallCartVo;
import com.yf.tz.vo.MallOrderVo;
import com.yf.tz.vo.OrderCommitVo;
import com.yf.tz.vo.down.MallOrderDown;
import com.yf.tz.vo.down.MallOrderSendDown;
import com.yf.tz.vo.down.MallOrderSumDown;
import com.yf.tz.vo.res.CommitOrderRes;
import com.yf.tz.vo.up.MallOrderUp;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单Service实现类
 *
 * @author hxf
 * @email 505860922@qq.com
 * @date Wed Jul 01 16:32:18 CST 2020
 */
@Service
public class MallOrderServiceImpl extends BaseServiceImpl<MallOrderEntity> implements MallOrderService {

    private MallOrderDao mallOrderDao;

    @Autowired
    private WxPayService wxPayService;


    @Autowired
    private UserDao userDao;


    @Autowired
    public void setDao(MallOrderDao mallOrderDao) {
        this.mallOrderDao = mallOrderDao;
        super.setBaseDao(mallOrderDao);
    }


    @Override
    public List<MallOrderVo> queryListVo(MallOrderVo mallOrderVo) {
        return mallOrderDao.queryListVo(mallOrderVo);
    }

    @Override
    public MallOrderVo getVo(Long id) {
        MallOrderVo vo = mallOrderDao.getVo(id);
        List<MallItemEntity> items = mallItemDao.findByOrderId(vo.getMallOrder().getId());
        vo.getMallOrder().setItems(items);
        return vo;
    }


    /**内部方法**/


    /**
     * 外部方法实现
     **/


    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommitOrderRes commitOrder(Long userId, OrderCommitVo orderCommitVo, HttpServletRequest request) {
        CommitOrderRes res = new CommitOrderRes();
        MallAddressEntity addressEntity = addressDao.get(orderCommitVo.getAddressId());
        if(orderCommitVo.getPayWay()==-1){
            orderCommitVo.setPayWay(0);
        }
        MallOrderEntity mallOrderEntity = new MallOrderEntity(createNO(userId), MallOrderPaidEnum.NO.getIndex(), new Date(), MallOrderOrderStatusEnum.NEW.getIndex(), addressEntity.getProvince(), addressEntity.getCity(), addressEntity.getCounty(), addressEntity.getDetail(), addressEntity.getMobile(), addressEntity.getName(), userId, orderCommitVo.getPayWay(), orderCommitVo.getRemark());
        mallOrderDao.save(mallOrderEntity);
        res.setOrderId(mallOrderEntity.getId());
        //计算订单
        countOrder(mallOrderEntity, orderCommitVo.getItems());
        //支付之前 扣掉券之类的 计算实际需要支付的钱
        beforePay(mallOrderEntity);
        //不需要付款直接返回
        if(mallOrderEntity.getPay().compareTo(BigDecimal.ZERO)<=0){
            afterPay(mallOrderEntity);
            res.setPaid(true);
            return res;
        }
        //存储金支付
        if (orderCommitVo.getPayWay().equals(MallOrderPayWayEnum.CEC.getIndex())) {
            accountService.useCash(userId, mallOrderEntity.getPay(), "商城下单支付", mallOrderEntity.getOrderNo());
            afterPay(mallOrderEntity);
            res.setPaid(true);
        } else {//微信支付
            UserEntity userEntity = userDao.get(mallOrderEntity.getUserId());
            String noticeUrl = ServletUriComponentsBuilder.fromContextPath(request).path(Const.MALL_ORDER_PAY_NOTICE_URL).toUriString();
            String param = wxPayService.createAppConfig(mallOrderEntity.getOrderNo(),mallOrderEntity.getPay().doubleValue(),"商城的订单",userEntity.getOpenId(), noticeUrl);
            res.setWxPayParam(param);
        }
        return res;
    }

    @Override
    public String rePay(Long userId,Long orderId) {
        UserEntity userEntity = userDao.get(userId);
        MallOrderEntity orderEntity = get(orderId);
        if(orderEntity==null){
            throw new RRException("订单不存在!");
        }
        //已经支付 或者不是新订单
        if(orderEntity.getPaid().equals(MallOrderPaidEnum.YES.getIndex())||!orderEntity.getOrderStatus().equals(MallOrderOrderStatusEnum.NEW.getIndex())){
            throw new RRException("禁止支付");
        }
        String noticeUrl = ServletUriComponentsBuilder.fromCurrentContextPath().path(Const.MALL_ORDER_PAY_NOTICE_URL).build().toUriString();
        String res = wxPayService.createAppConfig(orderEntity.getOrderNo(),orderEntity.getPay().doubleValue(),"商城订单",userEntity.getOpenId(),noticeUrl);
        return res;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MallOrderEntity cancelOrder(Long userId, Long orderId) {
        //判断是否是自己的订单
        MallOrderEntity orderEntity = mallOrderDao.get(orderId);
        if (orderEntity == null) {
            throw new RRException("订单不存在!");
        }
        if (userId!=null&&!orderEntity.getUserId().equals(userId)) {
            throw new RRException("非法操作");
        }
        if (orderEntity.getOrderStatus().equals(MallOrderOrderStatusEnum.CANCELED.getIndex())) {
            throw new RRException("请勿重复操作!");
        }
        //资金操作
        accountService.cancelOrder(orderEntity);
        //退回库存
        increaseStock(orderId);
        //修改状态
        orderEntity.setOrderStatus(MallOrderOrderStatusEnum.CANCELED.getIndex());
        mallOrderDao.update(orderEntity);
        return orderEntity;
    }

    //增加库存
    void  increaseStock(Long orderId){
        List<MallItemEntity> items = mallItemDao.findByOrderId(orderId);
        items.forEach(item->{
            mallGoodsService.increaseStock(item.getGoodsId(),item.getSkuId(),item.getQuantity());
        });
    }

//
//    //减少库存
//    void decreaseStock(Long orderId) {
//        List<MallItemEntity> items = mallItemDao.findByOrderId(orderId);
//        items.forEach(item -> {
//            mallGoodsService.decreaseStock(item.getGoodsId(), item.getSkuId(), item.getQuantity());
//        });
//    }

    //创建订单号
    private String createNO(Long userId) {
        return System.currentTimeMillis() + "" + Math.round(Math.random() * 100) + "" + userId;
    }

    //支付之前 扣掉积分
    private void beforePay(MallOrderEntity orderEntity) {
        countPay(orderEntity);
    }

    @Autowired
    private LevelDao levelDao;

    private void countPay(MallOrderEntity orderEntity) {
        //扣掉使用的积分
        accountService.usePoint(orderEntity.getUserId(), orderEntity.getPoint(), "积分换购", orderEntity.getOrderNo());
        //设置实际需要支付的钱 会员抵扣
        LevelEntity levelEntity = levelDao.findByUserId(orderEntity.getUserId());
        BigDecimal pay = orderEntity.getPrice();
//        if(levelEntity.getOff()!=null){
//            pay = pay.multiply(levelEntity.getOff()).setScale(2);
//        }
        //计算邮费
        countLogFee(orderEntity);
        pay = pay.add(orderEntity.getLogFee());
        orderEntity.setPay(pay);
        update(orderEntity);
    }

    @Autowired
    private ServerConfigService configService;

    private void countLogFee(MallOrderEntity orderEntity){
        ServerConfigEntity configEntity = configService.findConfig();
        BigDecimal tem = configEntity.getMailFee();
        //商品金额大于等于包邮价格
        if(orderEntity.getPrice().compareTo(configEntity.getMailFree())>=0){
            tem= BigDecimal.ZERO;
        }
        orderEntity.setLogFee(tem);
    }

    //支付之后 TODO 扣减库存
    @Transactional(rollbackFor = Exception.class)
    public void afterPay(MallOrderEntity orderEntity) {
        orderEntity.setPaid(MallOrderPaidEnum.YES.getIndex());
        orderEntity.setPayTime(new Date());
        mallOrderDao.update(orderEntity);
//        decreaseStock(orderEntity.getId());
        //通知系统管理员
//        MallOrderVo vo = mallOrderDao.getVo(orderEntity.getId());
//        msgHandler.sendMallOrder(Constant.SUPER_ADMIN,vo);
    }

//    @Autowired
//    private StompMsgHandler msgHandler;


    /**
     * 生成订单清单
     * 计算清单总数
     * 扣减货物库存
     * TODO 计算物流费
     *
     * @param orderEntity
     * @param items
     * @return
     */
    private List<MallItemEntity> countOrder(MallOrderEntity orderEntity, List<MallCartVo> items) {
        UserEntity userEntity = userDao.get(orderEntity.getUserId());
        BigDecimal totalPrice = BigDecimal.ZERO;
        Integer totalQuantity = 0;
        BigDecimal totalPoint = BigDecimal.ZERO;
        BigDecimal logFee = BigDecimal.ZERO;
        List<MallItemEntity> res = new ArrayList<>();
        for (MallCartVo cartVo : items) {
            MallItemEntity itemEntity = buildItem(orderEntity.getId(), cartVo);
            if(itemEntity.getName().contains("积分")){//买了积分产品
                if(userEntity.getBankNum()==null||userEntity.getBankNum().equals("")){
                    throw new RRException("请先在个人中心完善卡号!");
                }
            }
            if (itemEntity.getPoint() != null) {
                totalPoint = totalPoint.add(itemEntity.getPoint().multiply(new BigDecimal(cartVo.getNumber())));
            }
            totalQuantity += itemEntity.getQuantity();
            totalPrice = totalPrice.add(itemEntity.getPrice().multiply(new BigDecimal(cartVo.getNumber())));
            res.add(itemEntity);
        }
        orderEntity.setLogFee(logFee);
        orderEntity.setItems(res);
        orderEntity.setQuantity(totalQuantity);
        orderEntity.setPrice(totalPrice);
        orderEntity.setPoint(totalPoint);
        mallOrderDao.update(orderEntity);
        return res;
    }

    @Autowired
    private MallGoodsService mallGoodsService;

    //打包 减库存
    private MallItemEntity buildItem(Long orderId, MallCartVo cartVo) {
        Long goodsId = cartVo.getGoodsId();
        Long skuId = cartVo.getSkuId();
        Integer quantity = cartVo.getNumber();
        //直接扣减库存
        mallGoodsService.decreaseStock(goodsId,skuId,quantity);
        MallGoodsEntity goodsEntity = mallGoodsDao.get(goodsId);
        String img = goodsEntity.getMinImg();
        BigDecimal price = goodsEntity.getNowPrice();
        BigDecimal point = goodsEntity.getPoint();
        BigDecimal oldPrice = goodsEntity.getOldPrice();
        BigDecimal weight = goodsEntity.getWeight();
        String skuName = "";
        //如果选了规格
        if (skuId != null) {
            MallSkuEntity mallSkuEntity = mallSkuDao.get(skuId);
            price = mallSkuEntity.getPrice();
            point = mallSkuEntity.getPoint();
            weight = mallSkuEntity.getWeight();
            skuName = mallSkuEntity.getName();
            if (mallSkuEntity.getImg() != null && !mallSkuEntity.getImg().equals("")) {
                img = mallSkuEntity.getImg();
            }
        }
        MallItemEntity mallItemEntity = new MallItemEntity(orderId, goodsEntity.getName(), skuName, quantity, skuId, goodsId, price, oldPrice, img, weight, point);
        mallItemDao.save(mallItemEntity);
        return mallItemEntity;
    }

    @Override
    public List<MallOrderVo> findByUserId(Long userId, Integer paid, Integer status, Integer page, Integer limit) {
        PageHelper.startPage(page, limit).setOrderBy("mallOrder.id desc");
        List<MallOrderVo> list = mallOrderDao.findByUserId(userId, paid, status);
        //组装list
        for (MallOrderVo vo : list) {
            List<MallItemEntity> items = mallItemDao.findByOrderId(vo.getMallOrder().getId());
            vo.getMallOrder().setItems(items);
        }
        return list;
    }

    @Override
    public MallOrderEntity findByOrderNo(String orderNo) {
        return mallOrderDao.findByOrderNo(orderNo);
    }

    @Override
    public void downLoad(HttpServletResponse response, List<MallOrderEntity> list) {
        try {
            List<MallOrderDown> datas = list.stream().map(item -> {
            UserEntity user = userDao.get(item.getUserId());
             MallOrderDown down =   new MallOrderDown(item);
             down.setBankInfo(user.getBankName()+" " + user.getBankBranch()+ " "+user.getBankNum() + " " + user.getBankUser());
            return down;
            }).collect(Collectors.toList());
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("测试", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), MallOrderDown.class).sheet("模板").doWrite(datas);
        } catch (Exception e) {
            e.printStackTrace();
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, String> map = new HashMap<String, String>();
            map.put("status", "failure");
            map.put("message", "下载文件失败" + e.getMessage());
            try {
                response.getWriter().println(JSON.toJSONString(map));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void downLoadSend(HttpServletResponse response) {
        //找到所有支付但是未发货的订单
        List<MallOrderVo> vos = mallOrderDao.findByStatusAndPaid(MallOrderOrderStatusEnum.NEW.getIndex(), MallOrderPaidEnum.YES.getIndex());
        if(vos.isEmpty()){
            throw new RRException("没有需要发货的订单");
        }
        //订单ID集合
        List<Long> ids = vos.stream().map(vo->vo.getMallOrder().getId()).collect(Collectors.toList());
        mallOrderDao.waitSend(ids,MallOrderOrderStatusEnum.NEW.getIndex());
        //产品累计
        Map<String, Integer> sumMap = new HashMap<>();
        //明细集合
        List<MallOrderSendDown> orderDowns = new ArrayList<>();
        //汇总集合
        List<MallOrderSumDown> sumDowns = new ArrayList<>();
        vos.forEach(vo -> {
            List<MallItemEntity> itemEntities = mallItemDao.findByOrderId(vo.getMallOrder().getId());
            StringBuffer sb = new StringBuffer();
            //统计总数
            itemEntities.forEach(item -> {
                if (item.getSkuName() != null) {
                    String key = item.getName() + item.getSkuName();
                    Integer quantity = 0;
                    if (sumMap.containsKey(item.getName())) {
                        quantity = sumMap.get(item.getName());
                    }
                    quantity += item.getQuantity();
                    sumMap.put(key, quantity);
                    sb.append(key).append("X").append(item.getQuantity()).append(" ");
                }
            });
            //生成明细下载模板
            MallOrderSendDown sendDown = new MallOrderSendDown();
            sendDown.setUserName(vo.getMallOrder().getName());
            sendDown.setMobile(vo.getMallOrder().getPhone());
            sendDown.setAddress(vo.getMallOrder().getAddress());
            sendDown.setDetail(sb.toString());
            sendDown.setLogFee(vo.getMallOrder().getLogFee());
            sendDown.setOrderNo(vo.getMallOrder().getOrderNo());
            sendDown.setQuantity(vo.getMallOrder().getQuantity());
            sendDown.setRemark(vo.getMallOrder().getRemark());
            sendDown.setId(vo.getMallOrder().getId());
            sendDown.setBankInfo(vo.getUser().getBankName()+" "+vo.getUser().getBankBranch()+" "+vo.getUser().getBankNum()+" "+vo.getUser().getBankUser());
            orderDowns.add(sendDown);
        });
        //生成汇总下载模板
        sumMap.keySet().forEach(key -> {
            MallOrderSumDown sumDown = new MallOrderSumDown(key, sumMap.get(key));
            sumDowns.add(sumDown);
        });
        //更新
        if (ids.size() > 0) {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename=demo.xlsx");
            try {
                ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
                WriteSheet writeSheet1 = EasyExcel.writerSheet(0, "订单").head(MallOrderSendDown.class).build();
                excelWriter.write(orderDowns, writeSheet1);
                WriteSheet writeSheet2 = EasyExcel.writerSheet(1, "汇总").head(MallOrderSumDown.class).build();
                excelWriter.write(sumDowns, writeSheet2);
                excelWriter.finish();
                mallOrderDao.waitSend(ids, MallOrderOrderStatusEnum.DELIVERING.getIndex());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetWaitSend() {
        mallOrderDao.resetWaitSend(MallOrderOrderStatusEnum.DELIVERING.getIndex(), MallOrderOrderStatusEnum.NEW.getIndex());
    }

    @Override
    public void upload(InputStream inputStream) {
        EasyExcel.read(inputStream, MallOrderUp.class, new UploadDataListener()).sheet().doRead();
    }

    class UploadDataListener extends AnalysisEventListener<MallOrderUp> {


        @Override
        @Transactional(rollbackFor = Exception.class)
        public void invoke(MallOrderUp orderUpVo, AnalysisContext analysisContext) {
            MallOrderEntity mallOrderEntity = mallOrderDao.get(orderUpVo.getId());
            mallOrderEntity.setLogCompany(orderUpVo.getLogCompany());
            mallOrderEntity.setLogNo(orderUpVo.getLogNo());
            mallOrderEntity.setOrderStatus(MallOrderOrderStatusEnum.DELIVERED.getIndex());
            mallOrderEntity.setSendTime(new Date());
            mallOrderEntity.setLogFee(orderUpVo.getLogFee());
            mallOrderDao.update(mallOrderEntity);
            //通知发货 TODO
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {

        }

    }

    @Autowired
    private WxNoticeService noticeService;

    //TODO 填写模板 然后发送
    private void notice(MallOrderEntity orderEntity){
        UserEntity userEntity = userDao.get(orderEntity.getUserId());
        Map map = new HashMap();
        map.put("first","商品已经发出");
        map.put("delivername",orderEntity.getLogCompany());
        map.put("ordername",orderEntity.getLogNo());
        map.put("remark","注意查收！");
        noticeService.send(userEntity.getOpenId(),"gLFUWhYbPNNA9Va1-uklCIk77NTz3MSzpxqq_t9-5ck","",map);
    }


    @Autowired
    private MallAddressDao addressDao;

    @Autowired
    private MallSkuDao mallSkuDao;

    @Autowired
    private MallGoodsDao mallGoodsDao;

    @Autowired
    private MallItemDao mallItemDao;

    @Autowired
    private AccountService accountService;

}
